# -*- coding: utf-8 -*-
import libxml2dom
import mechanize
import urllib


TUENTI_HOST = "http://m.tuenti.com"
PROFILE_URL = "/?m=profile&user_id="
URLS = {
    'login': TUENTI_HOST + "/?m=login&func=process_login",
    'friends': TUENTI_HOST + "/?m=friends&page=%s",
    'profile': TUENTI_HOST + "/?m=profile&user_id=%s",
    'comments': TUENTI_HOST + "/?m=profile&func=view_wall&user_id=%s&fpi=%s",
    'my_profile': TUENTI_HOST + "/?m=profile&func=my_profile",
    'set_status': TUENTI_HOST + "/?m=profile&func=process_set_status&from=home&csfr=%s",
    'create_blog_entry': TUENTI_HOST + "/?t=profile_send_blog&ot=blog_entry&m=blog_entry&uid=%s",
}
MESSAGES = {
    'login_error': "<small>Dirección de correo o contraseña inválidos.</small>",
    'more_friends': ">Ver más amigos</a>",
    'more_comments': ">Ver más comentarios del tablón</a>",
    'wall': u"Tablón de",
    'my_wall': u"Mi tablón",
    'restricted_area': "<div class=\"h\">Acceso Restringido</div>",
    'status': "<b>Estado</b>",
    'status_verb': u"está",
}
HTTP_RESPONSE_CODES = {
    'OK': 200,
    'CREATED': 201,
    'ACCEPTED': 202,
    'BAD_REQUEST': 400,
    'UNAUTHORIZED': 401,
    'NOT_FOUND': 404,
    'CONFLICT': 409,
    'PRECONDITION_FAILED': 412
}


class StatusException(Exception):
    """Response Error class"""
    def __init__(self, value, result=None):
        self.value = value
        self.responses = {
        100: ('Continue', 'Request received, please continue'),
        101: ('Switching Protocols',
              'Switching to new protocol; obey Upgrade header'),
        200: ('OK', 'Request fulfilled, document follows'),
        201: ('Created', 'Document created, URL follows'),
        202: ('Accepted',
              'Request accepted, processing continues off-line'),
        203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
        204: ('No Content', 'Request fulfilled, nothing follows'),
        205: ('Reset Content', 'Clear input form for further input.'),
        206: ('Partial Content', 'Partial content follows.'),
        300: ('Multiple Choices',
              'Object has several resources -- see URI list'),
        301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
        302: ('Found', 'Object moved temporarily -- see URI list'),
        303: ('See Other', 'Object moved -- see Method and URL list'),
        304: ('Not Modified',
              'Document has not changed since given time'),
        305: ('Use Proxy',
              'You must use proxy specified in Location to access this '
              'resource.'),
        307: ('Temporary Redirect',
              'Object moved temporarily -- see URI list'),
        400: ('Bad Request',
              'Bad request syntax or unsupported method'),
        401: ('Unauthorized',
              'No permission -- see authorization schemes'),
        402: ('Payment Required',
              'No payment -- see charging schemes'),
        403: ('Forbidden',
              'Request forbidden -- authorization will not help'),
        404: ('Not Found', 'Nothing matches the given URI'),
        405: ('Method Not Allowed',
              'Specified method is invalid for this server.'),
        406: ('Not Acceptable', 'URI not available in preferred format.'),
        407: ('Proxy Authentication Required', 'You must authenticate with '
              'this proxy before proceeding.'),
        408: ('Request Timeout', 'Request timed out; try again later.'),
        409: ('Conflict', 'Request conflict.'),
        410: ('Gone',
              'URI no longer exists and has been permanently removed.'),
        411: ('Length Required', 'Client must specify Content-Length.'),
        412: ('Precondition Failed', 'Precondition in headers is false.'),
        413: ('Request Entity Too Large', 'Entity is too large.'),
        414: ('Request-URI Too Long', 'URI is too long.'),
        415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
        416: ('Requested Range Not Satisfiable',
              'Cannot satisfy request range.'),
        417: ('Expectation Failed',
              'Expect condition could not be satisfied.'),
        500: ('Internal Server Error', 'Server got itself in trouble'),
        501: ('Not Implemented',
              'Server does not support this operation'),
        502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
        503: ('Service Unavailable',
              'The server cannot process the request due to a high load'),
        504: ('Gateway Timeout',
              'The gateway server did not receive a timely response'),
        505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
        }
        if result:
            self.result = "\n%s" % result

    def __str__(self):
        return "Error [%s]: %s. %s.%s" % (self.value,
            self.responses[self.value][0], self.responses[self.value][1],
            self.result)


class API(object):
    """Main class"""
    def __init__(self, email, password, *args, **kwargs):
        self._br = mechanize.Browser()
        data = {'email': email, 'password': password}
        self.encoded_data = urllib.urlencode(data)
        response = self._br.open(URLS['login'], self.encoded_data)
        status = response.code
        body = response.read()
        if (status == HTTP_RESPONSE_CODES['OK'] and
            MESSAGES['login_error'] not in body):
            self.Profile = Profile(self._br)
            self.Friends = Friends(self._br)
            self.Comments = Comments(self._br, self.Profile.id)
        else:
            raise StatusException(401, "Email or password are invalid.")


class User(object):
    """User base class"""
    def __init__(self, br, user_id, *args, **kwargs):
        self._br = br
        self.id = user_id

    def _get_first_name(self):
        pass
    first_name = property(_get_first_name)

    def _get_last_name(self):
        pass
    last_name = property(_get_last_name)

    def _get_name(self):
        pass
    name = property(_get_name)

    def _get_birthdate(self):
        pass
    birthdate = property(_get_birthdate)

    def _get_marital_status(self):
        pass
    marital_status = property(_get_marital_status)

    def _get_province(self):
        pass
    province = property(_get_province)

    def _get_locality(self):
        pass
    locality = property(_get_locality)

    def _get_hobbies(self):
        pass
    hobbies = property(_get_hobbies)

    def _get_films(self):
        pass
    films = property(_get_films)

    def _get_quotes(self):
        pass
    quotes = property(_get_quotes)

    def _get_music(self):
        pass
    music = property(_get_music)

    def _get_books(self):
        pass
    books = property(_get_books)


class Profile(User):
    """Profile class"""
    def __init__(self, br, *args, **kwargs):
        self._br = br
        user_id = self._get_user_id()
        if not user_id:
            raise StatusException(404, "User not found in tuenti.")
        else:
            super(Profile, self).__init__(br, user_id, *args, **kwargs)
        self._csfr = self._get_csfr()
        if not self._csfr:
            raise StatusException(404, "csfr key not found in profile.")

    def _get_user_id(self):
        response = self._br.open(URLS['my_profile'])
        status = response.code
        body = response.read()
        if status == HTTP_RESPONSE_CODES['OK']:
            doc = libxml2dom.parseString(body, html=1)
            fieldsets = doc.getElementsByTagName('fieldset')
            for fieldset in fieldsets:
                if fieldset.getAttribute('title') == MESSAGES['my_wall']:
                    anchor = fieldset.getElementsByTagName('a').pop()
                    user_id = anchor.getAttribute('href').split('user_id=')[1].split('&')[0]
                    return user_id

    def _get_csfr(self):
        response = self._br.open(TUENTI_HOST)
        status = response.code
        body = response.read()
        if status == HTTP_RESPONSE_CODES['OK']:
            doc = libxml2dom.parseString(body, html=1)
            forms = doc.getElementsByTagName('go')
            if forms:
                return forms[0].getAttribute('href').split('csfr=')[1].split('&')[0]

    def _set_status(self, value):
        if value:
            data = {'status': value}
        else:
            data = {'status': ""}
        self.encoded_data = urllib.urlencode(data)
        response = self._br.open(URLS['set_status'] % self._csfr, self.encoded_data)
        status = response.code
        body = response.read()
        if (status != HTTP_RESPONSE_CODES['OK'] or
            MESSAGES['restricted_area'] in body):
            raise StatusException(304, "Status not modified.")
    def _get_status(self):
        response = self._br.open(URLS['my_profile'])
        status = response.code
        body = response.read()
        if status == HTTP_RESPONSE_CODES['OK']:
            doc = libxml2dom.parseString(body, html=1)
            fieldsets = doc.getElementsByTagName("fieldset")
            for fieldset in fieldsets:
                if (len(fieldset.childNodes) > 2 and
                    fieldset.childNodes[0].toString() == MESSAGES['status']):
                    status_node_value = fieldset.childNodes[2].value
                    if status_node_value:
                        status_message = status_node_value.split(MESSAGES['status_verb'])[1].strip()
                        return status_message
        return None
    status = property(_get_status, _set_status)

    def _get_first_name(self):
        pass
    first_name = property(_get_first_name)

    def _get_last_name(self):
        pass
    last_name = property(_get_last_name)

    def _get_name(self):
        pass
    name = property(_get_name)


class Friends(object):
    """Friend collection class"""
    def __init__(self, br, *args, **kwargs):
        self._br = br
        cont = 0
        response = self._br.open(URLS['friends'] % str(cont))
        status = response.code
        body = response.read()
        self._friends = []
        while (status == HTTP_RESPONSE_CODES['OK'] and
               MESSAGES['more_friends'] in body):
            doc = libxml2dom.parseString(body, html=1)
            anchors = doc.getElementsByTagName('a')
            for anchor in anchors:
                if anchor and anchor.getAttribute('href').startswith(PROFILE_URL):
                    friend_dic = {}
                    friend_dic['user_id'] = anchor.getAttribute('href').split(PROFILE_URL)[1].split('&')[0]
                    friend_dic['nick'] = anchor.textContent
                    self._friends.append(friend_dic)
            cont = cont + 1
            response = self._br.open(URLS['friends'] % str(cont))
            status = response.code
            body = response.read()
        doc = libxml2dom.parseString(body, html=1)
        anchors = doc.getElementsByTagName('a')
        for anchor in anchors:
            if anchor and anchor.getAttribute('href').startswith(PROFILE_URL):
                friend_dic = {}
                friend_dic['user_id'] = anchor.getAttribute('href').split(PROFILE_URL)[1].split('&')[0]
                friend_dic['nick'] = anchor.textContent
                self._friends.append(friend_dic)

    def get(self, index):
        f = self._friends[index]
        return Friend(self._br, f.get('user_id', None), f.get('nick', None))

    def all(self):
        friend_list = []
        for f in self._friends:
            friend_list.append(Friend(self._br, f.get('user_id', None), f.get('nick', None)))
        return friend_list


class Friend(User):
    """Friend base class"""
    def __init__(self, br, user_id, nick, *args, **kwargs):
        super(Friend, self).__init__(br, user_id, *args, **kwargs)
        self.nick = nick
        self.Comments = Comments(self._br, user_id)


class Comments(object):
    """Comment collection class"""
    def __init__(self, br, user_id, *args, **kwargs):
        self._br = br
        self.user_id = user_id
        cont = 0
        response = self._br.open(URLS['comments'] % (self.user_id, cont))
        status = response.code
        body = response.read()
        self._comments = []
        while(status == HTTP_RESPONSE_CODES['OK'] and
              MESSAGES['more_comments'] in body):
            doc = libxml2dom.parseString(body, html=1)
            fieldsets = doc.getElementsByTagName('fieldset')
            for fieldset in fieldsets:
                if (fieldset.getAttribute('title') and
                    (fieldset.getAttribute('title') == MESSAGES['my_wall'] or
                     fieldset.getAttribute('title').startswith(MESSAGES['wall']))):
                    smalls = fieldset.getElementsByTagName('small')
                    for small in smalls[1:]:
                        comment_dic = {}
                        anchor = small.getElementsByTagName('a')[0]
                        if anchor and '?m=profile&user_id' in anchor.getAttribute('href'):
                            comment_dic.update({'friend_id': anchor.getAttribute('href').split('user_id=')[1]})
                            comment_dic.update({'friend_name': anchor.textContent})
                            text = anchor.nextSibling.textContent
                            splitted_text = text.split('(')
                            time =  splitted_text.pop()
                            time_parsed = time.split(')')[0]
                            text_parsed = text[2:len(text)-len(time)-3]
                            comment_dic.update({'text': text_parsed})
                            comment_dic.update({'time': time_parsed})
                            self._comments.append(comment_dic)
            cont = cont + 3
            response = self._br.open(URLS['comments'] % (self.user_id, cont))
            status = response.code
            body = response.read()
        doc = libxml2dom.parseString(body, html=1)
        fieldsets = doc.getElementsByTagName('fieldset')
        for fieldset in fieldsets:
            if (fieldset.getAttribute('title') and
                (fieldset.getAttribute('title') == MESSAGES['my_wall'] or
                 fieldset.getAttribute('title').startswith(MESSAGES['wall']))):
                smalls = fieldset.getElementsByTagName('small')
                for small in smalls[1:]:
                    comment_dic = {}
                    anchor = small.getElementsByTagName('a')[0]
                    if anchor and '?m=profile&user_id' in anchor.getAttribute('href'):
                        comment_dic.update({'friend_id': anchor.getAttribute('href').split('user_id=')[1]})
                        comment_dic.update({'friend_name': anchor.textContent})
                        text = anchor.nextSibling.textContent
                        splitted_text = text.split('(')
                        time =  splitted_text.pop()
                        time_parsed = time.split(')')[0]
                        text_parsed = text[2:len(text)-len(time)-3]
                        comment_dic.update({'text': text_parsed})
                        comment_dic.update({'time': time_parsed})
                        self._comments.append(comment_dic)


    def get(self, index):
        # TODO: Create an Friend instance
        return self._comments[index]

    def all(self):
        # TODO: Retrieve a Friend collection
        return self._comments

    def latest(self, entries=5):
        # TODO: Retrieve a Friend collection
        return self._comments[:entries]


class Comment(object):
    """Comment base class"""
    def __init__(self, br, user_id, *args, **kwargs):
        self._br = br
        self.user_id
        # TODO: Get Comment


__all__ = ['API']
